import bpy
from mathutils import Vector
from bpy.props import BoolProperty

from sverchok.node_tree import SverchCustomTreeNode
from sverchok.data_structure import updateNode, match_long_repeat as mlr
from sverchok.dependencies import FreeCAD
from sverchok.utils.curve.freecad import SvSolidEdgeCurve
from sverchok.utils.surface.freecad import SvSolidFaceSurface

if FreeCAD is not None:
    from FreeCAD import Base
    import Part


class SvSliceSolidNode(SverchCustomTreeNode, bpy.types.Node):
    """
    Triggers: Apply Matrix to Solid
    Tooltip: Transform Solid with Matrix
    """
    bl_idname = 'SvSliceSolidNode'
    bl_label = 'Slice Solid'
    bl_icon = 'MESH_CUBE'
    sv_icon = 'SV_SLICE_SOLID'
    sv_category = "Solid Operators"
    sv_dependencies = {'FreeCAD'}

    flat_output: BoolProperty(
        name="Flat Output",
        default=False,
        update=updateNode)

    def sv_init(self, context):
        self.inputs.new('SvSolidSocket', "Solid")
        self.inputs.new('SvMatrixSocket', "Matrix")

        self.outputs.new('SvCurveSocket', "Edges")
        self.outputs.new('SvSurfaceSocket', "Faces")

    def draw_buttons(self, context, layout):
        layout.prop(self, 'flat_output')

    def process(self):
        if not any(socket.is_linked for socket in self.outputs):
            return

        solids_in = self.inputs[0].sv_get(deepcopy=False)
        matrixes = self.inputs[1].sv_get(deepcopy=False)
        slices = []
        slices_face = []
        faces_add = slices_face.extend if self.flat_output else slices_face.append
        slices_add = slices.extend if self.flat_output else slices.append

        for solid, matrix in zip(*mlr([solids_in, matrixes])):

            location = matrix.decompose()[0]
            norm = (matrix @ Vector((0, 0, 1))) - location
            dist = norm.dot(location)

            wires = solid.slice(Base.Vector(norm), dist)
            edges_curves = []
            faces = []
            for wire in wires:
                for edge in wire.Edges:
                    curve = SvSolidEdgeCurve(edge)
                    edges_curves.append(curve)

            if wires:
                face = Part.Face(wires)
                faces.append(SvSolidFaceSurface(face).to_nurbs())
            if faces:
                faces_add(faces)
            if edges_curves:
                slices_add(edges_curves)

        self.outputs['Edges'].sv_set(slices)
        self.outputs['Faces'].sv_set(slices_face)


def register():
    bpy.utils.register_class(SvSliceSolidNode)


def unregister():
    bpy.utils.unregister_class(SvSliceSolidNode)
